package gbench.sandbox.matrix.img;

import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.stream.*;
import java.awt.Color;

import gbench.common.fs.XlsFile.DataMatrix;
import gbench.sandbox.matrix.img.util.MatlibCanvas;
import gbench.sandbox.matrix.img.util.MatlibCanvas.Range;

import static java.lang.Math.*;
import static gbench.sandbox.matrix.img.util.ImageOps.*;
import static gbench.common.tree.LittleTree.*;

/**
 * 绘图
 * @author gbench
 *
 */
public class JunitMatlibCanvas {
    
    /**
	 * 绘图 <br>
     * 注意：此处的 线 除非特别说明，一般指 曲线，不一定 是直线，但也可以是 直线，即 一般意义上的 线。
	 * @param size 窗口大小
	 * @param plotflag 绘图标记，是否打开 图形窗口，true:打开,false:不打开
	 */
	public void plot(final Integer size,final Boolean plotflag) {
	    final var rng2pi = Range.of2(-PI, PI,2*PI/5000); // 一个周期的采样点区间
	    final var matlib = new MatlibCanvas(2*size); // 数学绘图（函数式的描述曲线）画布 组件
	    
	    // 绘制一张曲线图
	    final var img = matlib.plot( 2*size, size, pen -> {
	        // 默认颜色(红色)绘制一条线
	        pen.drawLine(x->sin(x/size*2*PI)*100+100);
	        
	        // 使用绿色绘制
	        pen.setColor(clr2rgb(Color.GREEN)); // 修改默认颜色为绿色
	        pen.drawLine(x->cos(x/size*2*PI)*100+100); // 默认颜色(绿色)绘制一条线
	        
	        // 画一条蓝线的直线
	        pen.drawLine(x->x,clr2rgb(Color.BLUE));
	        
	        // 水平线与垂直线的绘制方法
	        pen.setColor(clr2rgb(Color.WHITE)); // 修改默认颜色为白色
	        pen.drawLineX(x->100d); // 水平线 
	        pen.drawLineY(y->100d); // 垂直线
	        
	        // 画一条黄色的线
	        pen.setColor(clr2rgb(Color.YELLOW)); // 修改默认颜色为黄色
	        pen.drawLine(x->square(x)); // 默认色 平方数曲线
	        
	        // 画一条品红色的线
	        pen.drawLine(0,20,x->exp(x)/100,clr2rgb(Color.CYAN)); // 品红色线
	        pen.drawLine(x->0.7*x); // 默认色直线
	        
	        // 画直线
	        pen.drawStraightLine(x->-0.5*x+size,clr2rgb(Color.CYAN));// 默认色直线
	        pen.drawStraightLine(200,0,200,200,clr2rgb(Color.CYAN));// 默认色直线
	        pen.drawStraightLine(200,200,2*size,200,clr2rgb(Color.CYAN));// 默认色直线
	        
	        // 画一个圆
	        final var r = 150; // 半径
	        final var centerx = 500; // 圆心x
	        final var centery = 250; // 圆心y
	        pen.setColor(clr2rgb(Color.MAGENTA)); // 修改默认颜色为洋红色
	        pen.drawLines( Range.of2(-r,+r).add(centerx), // 首尾 双包含
	            x -> sqrt(square(r)-square(x-centerx)) + centery, // 上半圆
	            x -> -sqrt(square(r)-square(x-centerx)) + centery // 下半圆
	        );// drawLines
	        
	        // 画一个红色的圆
	        pen.setColor(clr2rgb(Color.RED)); // 修改默认颜色为红色
	        pen.drawPoints(rng2pi.map(theta->matlib.rhoTheta(theta).affine(r,r,centerx,centery)));
	        
	        // 画一个青色的椭圆
	        pen.setColor(clr2rgb(Color.CYAN)); // 修改默认颜色为 蓝绿色即青色
	        pen.drawPoints(rng2pi.map(matlib::rhoTheta).map(e->e.affine(r,r/3,centerx,centery)));// 水平
	        pen.drawPoints(rng2pi.map(matlib::rhoTheta).map(e->e.affine(r/3,r,centerx,centery)));// 垂直
	        
	        // 随机的画一些 噪声点
	        pen.drawPoints(Range.of(0, 50000).map(e->matlib.xY(rndint(size), rndint(size) ,rndrgb())));// drawPoints
	        
	        // pen.dump();
	    },plotflag); // 绘图
	    
	    // 查看画笔颜色
	    // System.out.println(rgb2clr(matlib.getColor()));
	    jpgwrite(img,"C:/Users/Administrator/Pictures/pics/a.jpg",Color.CYAN);
	    
	    // 绘制第二个窗口, 重新开启 会话 会 重置前一会话中 PenSession 所做的 环境设置
	    // 即 pen会话 的 设置 只能 在当前 会话 有效,不能跨越 会话，所以尽管 前一 会话 设置默认色 为n青色，但此处 会话 的默认色
	    // 依旧是matlib的 默认色：红色, 注意：通过 matlib.setColor 做的设置 是会 跨越 会话 的 更改 默认色。
	    matlib.plot(size, size, pen -> {
	        // 画一条线:默认颜色为红色
	        pen.drawLine(x->x);
	        
	        // 极坐标画圆
	        pen.setColor(clr2rgb(Color.YELLOW)); // 修改默认颜色为黄色
	        pen.drawPoints(rng2pi.map(theta->matlib.rhoTheta(100,theta).affine_offset(200)));
	        
	        // 绘制椭圆
	        pen.setColor(clr2rgb(Color.BLUE)); // 修改默认颜色为蓝色
	        pen.drawPoints(rng2pi.map(theta->matlib.rhoTheta(theta).affine(200,100,200,200)));
	        
	        // 绘制矩形:矩形是四条线 分为2组。水平组合垂直组
	        final var hrange = Range.of2(100,300); // 水平位置，x 范围 
	        final var vrange = Range.of2(100,300); // 垂直位置 ，y 范围
	        final var flag = System.currentTimeMillis() < 0; // 绘制方式的标记
	        if(!flag)
		        pen.drawPoints( hrange.reverseFlatMap( // 水平线
		            // rng用于规定点的数量,即 水平线的长度, rng.flatMap表示一下子绘制多个点: 这里是两个点start和end
		            rng->rng.flatMap(i->vrange.startEndS().map(v->matlib.xY(i,v))  ) 
		        )).drawPoints( vrange.reverseFlatMap( // 垂直线
		            // rng用于规定点的数量,即 垂直线的长度, rng.flatMap表一下子绘制多个点: 这里是两点start和end
		            rng->rng.flatMap(j->hrange.startEndS().map(h->matlib.xY(h,j))  ) 
		        ));// drawPoints
	        else  
		        pen.drawPoints( Stream.of(hrange,vrange).map(kvp()).flatMap( tup -> // [(0,水平跨度),(1,垂直跨度)]
		        	tup._2().reverseFlatMap( rng -> // rng : 当前数据的延展范围(0:水平方向,1:或垂直方向)
		        		rng.flatMap( i -> // i : 遍历当前rng时 的当前位置
		        			// 水平范围 使用 垂直高度,垂直范围使用水平高度
		        	    	( tup._1() == 0 ? vrange : hrange ).startEndS().map( const_value -> // 高低值 或是左右值
		        	    		// tup._1() == 0  表示 当前的 数据延展范围是 水平方向，x方向:为延展索引,y方向为:高度固定
		        	    		// tup._1() == 1  表示 当前的 数据延展范围是 垂直方向，y方向:为延展索引,x方向为:偏移固定,所以 此时需要 x,y 翻转
		        	            matlib.xY( i, const_value, tup._1() == 1 ) ) ) ) ) );
	    },plotflag); // plot
	    
	    /**
	     * 绘制节点矩阵<br>
	     * 注意结构range的范围从[5,10)
	     */
	    final var rgb = DataMatrix.of( matlib
	            .setRange(5,10)
	            .setColor(clr2rgb(Color.BLUE))
	            .drawLine3(x->x)
	        ,true).corece(e->rgb2clr(e).getBlue());
	    // 打印显示矩阵元素:垂直方向第一维数据。
	    System.out.println(rgb);
	}

	/**
	 * 区间范文检测
	 */
	@Test
	public void foo() {
	    System.out.println("end尾部包含");
	    Range.of(1, 10).intS().forEach(e->System.out.print(e+"\t"));
	    System.out.println();
	    Range.of(10, 1).intS().forEach(e->System.out.print(e+"\t"));
	    System.out.println();
	    Range.of(10, 1,0.5).reverse().dblStream().forEach(e->System.out.print(e+"\t"));
	    
	    System.out.println("\n\nend尾部包含");
	    Range.of2(1, 10).intS().forEach(e->System.out.print(e+"\t"));
	    System.out.println();
	    Range.of2(10, 1).intS().forEach(e->System.out.print(e+"\t"));
	}

	@Test
    public void bar() {
    	plot(size,plotflag);
    }
    
	@Test
	public void qux() {
		final var cc = MatlibCanvas.NVec.split("0123".split(""), 2);
		cc.forEach(e->{
			System.out.println(Arrays.deepToString(e));
		});
	}

	public Integer size=500; // 图片尺寸单位
	public Boolean plotflag=false; // 绘图标记
	
	/**
	 * 
	 * @param args
	 */
	public static void main(String args[]) {
		final var jmlc = new JunitMatlibCanvas();
		jmlc.plot(jmlc.size, true);
	}
    
}
